// Copyright 2011 Google Inc. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

/**
 * @fileoverview Provide functionality to support Chrome Extension's tabs API.
 * Only functionality that is not directly accessible in Firefox is implemented
 * here.
 *
 * @author jasonstredwick@google.com (Jason Stredwick)
 */


goog.provide('mimic.Tabs');

goog.require('console');



/**
 * Create an object to manage Chrome Extension's tabs API.
 * @constructor
 */
mimic.Tabs = function() {};


/**
 * "Destroys" the Tabs instance by "destroying" its data.
 */
mimic.Tabs.prototype.destroy = function() {};


/**
 * Sends a request from the background to the specified tab's content script.
 * @param {string} alias The alias of the owning extension.
 * @param {!Object} fromSandbox The sandbox object for the background unit that
 *     is sending the request.
 * @param {!Object} toUnits An object containing a mapping of units by id; can
 *     only send to content scripts.
 * @param {number} tabId The id of the content script's tab.
 * @param {Object} request The information to be sent out.  The request is
 *     expected to be a JSON-izable object.
 * @param {function(Object=)=} opt_response An optional callback to be called
 *     by the listeners who received the request.  The input to the callback
 *     is expected to be a JSON-izable object.
 * @export
 */
mimic.Tabs.prototype.sendRequest = function(alias, fromSandbox, toUnits,
                                            tabId, request, opt_response) {
  var msg = ''; // Message string used to report errors.

  // Determine toUnit related information.
  var toUnit = toUnits[tabId];
  if (!toUnit) {
    opt_response && opt_response(); // Already executing in appropriate sandbox
    return;
  }

  // Create an alias to the sandbox and signals for the unit the request is
  // being sent to.  The sandbox is Firefox construct used to evaluate
  // Javascript code that isolated from Javascript in the browser, page, and
  // other extensions.  The signals object provides a mapping of listeners and
  // functions to Chrome Extension API specifically for this toUnit.
  var toSandbox = toUnit.sandbox;
  var toSignals = toUnit.signals;

  // Prepare a function that will be executed in the toSandbox yet execute the
  // the given response in the fromSandbox; i.e. the original caller.
  var response = undefined;
  if (opt_response && typeof(opt_response) == 'function') {
    response = (function() {
      var f = function(data) {
        // A function that will return the data while inside the sandbox.
        var getData = function() {
          return data;
        };

        // Wrapper function that calls the response function while inside the
        // sandbox.
        var executeResponse = function() {
          // Clean up sandbox in case the flow of execution adds the same
          // items.
          var getData = fromSandbox['chrome']['tabs']['getData'];
          fromSandbox['chrome']['tabs']['getData'] = goog.nullFunction;
          fromSandbox['chrome']['tabs']['executeResponse'] =
              goog.nullFunction;

          opt_response(getData());
        };

        fromSandbox['chrome']['tabs']['getData'] = getData;
        fromSandbox['chrome']['tabs']['executeResponse'] =
            executeResponse;

        Components.utils.evalInSandbox('chrome.tabs.executeResponse();',
                                       fromSandbox);
      };

      return function(data) { f(data); };
    })();
  } else {
    msg = 'Invalid response given to chrome.tabs.sendRequest.';
    fromSandbox['chrome']['extension']['lastError'] = msg;
    console.error(msg);
    opt_response && opt_response(); // Already executing in appropriate sandbox
    return;
  }

  // Prepare sender
  var sender = {'id': alias};

  // Prepare to send request.
  var send = (function() {
    var f = function() {
      // Content scripts do not have access to the tabs api, so all temporary
      // functionality has to be added to the extensions api.
      toSandbox['chrome']['extension']['executeSend'] = goog.nullFunction;
      toSignals.extension.onRequest.fire(request, sender, response);
    };
    return function() { f(); };
  })();

  toSandbox['chrome']['extension']['executeSend'] = send;

  // Send request.
  Components.utils.evalInSandbox('chrome.extension.executeSend();', toSandbox);
};

